﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Grunwald.NOscar;

namespace IICQBot
{      
    /// <summary>
    /// Информация для подключения к серверу
    /// </summary>
    public struct LoginInfo
    {
        /// <summary>
        /// Имя сервера
        /// </summary>
        public string ServerName;
        /// <summary>
        /// Порт
        /// </summary>
        public int Port;
        /// <summary>
        /// Имя пользователя
        /// </summary>
        public string UserName;
        /// <summary>
        /// Пароль
        /// </summary>
        public string Password;
    }

    /// <summary>
    /// Фасад для интерфейса
    /// </summary>
    public abstract class AICQBot:IICQBot
    {
        private LoginInfo _logingInfo;
        private Grunwald.NOscar.AutomaticConnection _server;
        public AICQBot()
        {
            _logingInfo.ServerName = "login.icq.com";
            _logingInfo.Port = 1590;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Text"></param>
        private void addTextOnLog(String Text)
        {
            if (OnAddedLog != null)  OnAddedLog(this, new EventTools.EventArgs<string>(Text));
        }
        private void SendedMsg(string UIN, string TextMsg)
        {
            if (OnSendedMsg != null) OnSendedMsg(this, new EventTools.EventArgs<string, string>(UIN, TextMsg));
        }

        #region Члены IICQBot
        public event EventHandler<EventTools.EventArgs<string>> OnAddedLog;
        public event EventHandler<EventTools.EventArgs<string, string>> OnSendedMsg;

        /// <summary>
        /// Синхронное подключение к серверу
        /// </summary>
        /// <param name="UserName">Имя пользователя</param>
        /// <param name="Password">Пароль (Не шифрованный)</param>        
        /// <returns>Результат подключения</returns>
        public bool ConnectOnICQServer(string UserName, string Password)
        {
            addTextOnLog("Попытка подключения с серверу");

            _logingInfo.UserName = UserName;
            _logingInfo.Password = Password;

            addTextOnLog("Сервер - "+_logingInfo.ServerName);
            addTextOnLog("Порт - "    + _logingInfo.Port.ToString());
            addTextOnLog("UIN - "      + _logingInfo.UserName);

            _server = new AutomaticConnection(_logingInfo.ServerName, _logingInfo.Port, _logingInfo.UserName, _logingInfo.Password);            
            //Основные события работы протокола
            _server.StateChanged += new EventHandler(_server_StateChanged);
            _server.Sending           += new SnacEventHandler(_server_Sending);
            _server.SnacReceived  += new SnacEventHandler(_server_SnacReceived);
           
            //Запускаем подключение
            _server.Start(new System.Threading.ThreadExceptionEventHandler(ErrorHandler));
            return false;
        }

        void _server_SnacReceived(object sender, SnacEventArgs e)
        {          
            addTextOnLog("Сообщение - "+ e.Snac.SubType.ToString()+" "+e.Snac.GetType());
            
            if (e.Snac is UserMovedOnlineSnac)
            {
                UserMovedOnlineSnac _sender = (UserMovedOnlineSnac)e.Snac;
                foreach (UserInfo _ui in _sender.UserInfo)
                addTextOnLog("Пользователь " + _ui.Screenname + " - Онлайн");
            }

            if (e.Snac is UserMovedOfflineSnac)
            {
                UserMovedOfflineSnac _sender = (UserMovedOfflineSnac)e.Snac;
                addTextOnLog("Пользователь " + _sender.UserInfo[0].Screenname + " - ОФФЛайн");
            }
            
            //Сообщения от пользователя
            if (e.Snac is IncomingIcbmSnac)
            {
                IncomingIcbmSnac _sender = (IncomingIcbmSnac)e.Snac;
                string _uin = _sender.UserInfo.Screenname;
                string text = "";
                if (_sender.Channel == 1)
                {
                    MessageBlock msgData = new MessageBlock(_sender.DataChain.GetData(2));
                    text = msgData.GetText();
                }
                else
                    if (_sender.Channel == 4)
                    {
                        // Channel 4-ICBMs have their data stored as value 5 in the data chain.
                        byte[] msgData = _sender.DataChain.GetData(5);
                        // The class IcbmChannel4Data can interpret that data automatically.
                        IcbmChannel4Data data = new IcbmChannel4Data(msgData);
                        if (data.Type == MessageType.PlainText)
                        {
                            text = data.Message;
                        }
                        else
                        {
                            // Other types are system messages like Authorization Given/Denied etc.
                            text = data.Type.ToString() + " :: " + data.Message;
                        }
                    }
                addTextOnLog("Сообщение от пользователя " + _uin + " - " + text);
                SendedMsg(_uin, text);
            }


        }

        void _server_Sending(object sender, SnacEventArgs e)
        {
            addTextOnLog("Сообщение (Sending) - " + e.Snac.SubType.ToString() + " " + e.Snac.GetType());
        }
        /// <summary>
        /// Смена текущего статуса
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _server_StateChanged(object sender, EventArgs e)
        {
            AutomaticConnection _server = (AutomaticConnection) sender;
            switch (_server.State)
            {
                case ConnectionState.Dead:
                    {
                        addTextOnLog("Смена состояния - Dead");
                    }
                    break;
                case ConnectionState.Connecting:
                    {
                        addTextOnLog("Смена состояния - Connecting");
                    }
                    break;
                case ConnectionState.Connected:
                    {
                        addTextOnLog("Смена состояния - Connected");
                    }
                    break;
                case ConnectionState.Negotiating:
                    {
                        addTextOnLog("Смена состояния - Negotiating");
                    }
                    break;
                case ConnectionState.Active:
                    {
                        addTextOnLog("Смена состояния - Active");
                    }
                    break;                
            }
        }
        /// <summary>
        /// Обработчик критических ошибок
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ErrorHandler(object sender, System.Threading.ThreadExceptionEventArgs e)
        {

        }

        public bool SendMessage(string UIN, string Messages)
        {
            string text = Messages;
            string target = UIN;
            if (text.Length == 0) return false;

            TlvChain data = new TlvChain();
            MessageBlock block = new MessageBlock(text);

            data.SetData(0x0002, block.ToByteArray());
            data.SetFlag(0x0003);

            OutgoingIcbmSnac snac = new OutgoingIcbmSnac(1, target, data);

            Random rnd = new Random();
            rnd.NextBytes(snac.IcbmID);

            SendSnacSequence.SendSnac(_server, snac, null, null);
            return true;
        }
            
        #endregion
    }
}
